// Conditional Compilation (条件编译) 示例
// 演示 Pascal 中条件编译的各种用法
program p_38_conditional_compilation;

{$mode objfpc}{$H+}
// {$mode objfpc} 启用 Object Pascal 模式
// {$H+} 启用长字符串支持（AnsiString）

// 定义调试符号
{$DEFINE DEBUG}
{$DEFINE VERBOSE}

// 根据不同平台定义特定符号
{$IFDEF WINDOWS}
  {$DEFINE GUI_APP}
{$ENDIF}

{$IFDEF LINUX}
  {$DEFINE CONSOLE_APP}
{$ENDIF}

// 取消定义符号示例
{$IFDEF SOME_SYMBOL}
  {$UNDEF SOME_SYMBOL}
{$ENDIF}

uses
  SysUtils,
  Classes
  {$IFDEF GUI_APP}
    , Graphics  // 仅在GUI应用中使用
  {$ENDIF}
  {$IFDEF CONSOLE_APP}
    , Unix      // 仅在Unix/Linux系统中使用
  {$ENDIF}
  ;

// 自定义类型
type
  TLogLevel = (llError, llWarning, llInfo, llDebug);

// 条件编译的函数
procedure LogMessage(Level: TLogLevel; const Msg: String);
begin
  {$IFDEF VERBOSE}
    case Level of
      llError: Write('错误: ');
      llWarning: Write('警告: ');
      llInfo: Write('信息: ');
      llDebug: Write('调试: ');
    end;
    WriteLn(Msg);
  {$ELSE}
    // 在非VERBOSE模式下，只输出错误信息
    if Level = llError then
      WriteLn('错误: ', Msg);
  {$ENDIF}
  
  {$IFDEF DEBUG}
    // 在调试模式下，输出额外的调试信息
    if Level = llDebug then
      WriteLn('  [调试信息: ', FormatDateTime('hh:nn:ss.zzz', Now), ']');
  {$ENDIF}
end;

// 条件编译的过程
procedure PlatformSpecificCode;
begin
  WriteLn('平台特定代码:');
  
  {$IFDEF WINDOWS}
    WriteLn('  当前运行在 Windows 系统上');
    {$IFDEF WIN32}
      WriteLn('  32位 Windows 系统');
    {$ENDIF}
    {$IFDEF WIN64}
      WriteLn('  64位 Windows 系统');
    {$ENDIF}
  {$ENDIF}
  
  {$IFDEF LINUX}
    WriteLn('  当前运行在 Linux 系统上');
    {$IFDEF CPUARM}
      WriteLn('  ARM 架构处理器');
    {$ENDIF}
    {$IFDEF CPUX86}
      WriteLn('  x86 架构处理器');
    {$ENDIF}
    {$IFDEF CPUX64}
      WriteLn('  x64 架构处理器');
    {$ENDIF}
  {$ENDIF}
  
  {$IFDEF DARWIN}
    WriteLn('  当前运行在 macOS 系统上');
  {$ENDIF}
  
  {$IFNDEF WINDOWS}
    {$IFNDEF LINUX}
      {$IFNDEF DARWIN}
        WriteLn('  未知操作系统');
      {$ENDIF}
    {$ENDIF}
  {$ENDIF}
end;

// 使用条件表达式的示例
procedure ConditionalExpressionExample;
var
  value: Integer = 42;
begin
  WriteLn('条件表达式示例:');
  
  {$IF FPC_FULLVERSION >= 30000}
    WriteLn('  使用的是 FreePascal 3.0.0 或更高版本');
  {$ELSE}
    WriteLn('  使用的是 FreePascal 3.0.0 以下版本');
  {$ENDIF}
  
  {$IF sizeof(Pointer) = 8}
    WriteLn('  64位平台');
  {$ELSE}
    WriteLn('  32位平台');
  {$ENDIF}
  
  {$IF value > 0}
    WriteLn('  value(', value, ') 是正数');
  {$ENDIF}
  
  {$IF value mod 2 = 0}
    WriteLn('  value(', value, ') 是偶数');
  {$ENDIF}
end;

// 功能开关示例
procedure FeatureToggleExample;
begin
  WriteLn('功能开关示例:');
  
  {$IFDEF DEBUG}
    WriteLn('  调试模式已启用');
    WriteLn('  编译时间: ', {$I %DATE%}, ' ', {$I %TIME%});
  {$ELSE}
    WriteLn('  发布模式');
  {$ENDIF}
  
  {$IFDEF VERBOSE}
    WriteLn('  详细日志模式已启用');
  {$ELSE}
    WriteLn('  简洁日志模式');
  {$ENDIF}
  
  // 模拟一个可选功能
  {$IFDEF ADVANCED_FEATURE}
    WriteLn('  高级功能已启用');
  {$ELSE}
    WriteLn('  基础功能');
  {$ENDIF}
end;

// 条件编译的函数示例
function GetPlatformString: String;
begin
  {$IFDEF WINDOWS}
    Result := 'Windows';
  {$ENDIF}
  
  {$IFDEF LINUX}
    Result := 'Linux';
  {$ENDIF}
  
  {$IFDEF DARWIN}
    Result := 'macOS';
  {$ENDIF}
  
  {$IFNDEF WINDOWS}
    {$IFNDEF LINUX}
      {$IFNDEF DARWIN}
        Result := 'Unknown';
      {$ENDIF}
    {$ENDIF}
  {$ENDIF}
end;

// 程序主入口
begin
  WriteLn('=== Pascal 条件编译示例 ===');
  WriteLn;
  
  // 1. 基本条件编译示例
  WriteLn('1. 基本条件编译示例:');
  LogMessage(llInfo, '这是一条信息日志');
  LogMessage(llDebug, '这是一条调试日志');
  LogMessage(llError, '这是一条错误日志');
  
  WriteLn;
  
  // 2. 平台特定代码
  WriteLn('2. 平台特定代码:');
  PlatformSpecificCode;
  WriteLn('  检测到的平台: ', GetPlatformString);
  
  WriteLn;
  
  // 3. 条件表达式示例
  WriteLn('3. 条件表达式示例:');
  ConditionalExpressionExample;
  
  WriteLn;
  
  // 4. 功能开关示例
  WriteLn('4. 功能开关示例:');
  FeatureToggleExample;
  
  WriteLn;
  
  // 5. 条件编译与Uses子句的结合
  WriteLn('5. 条件编译与Uses子句的结合:');
  WriteLn('  根据平台条件编译引入了不同的单元');
  WriteLn('  当前引入的单元:');
  WriteLn('    - SysUtils (总是引入)');
  WriteLn('    - Classes (总是引入)');
  {$IFDEF GUI_APP}
    WriteLn('    - Graphics (仅Windows平台引入)');
  {$ENDIF}
  {$IFDEF CONSOLE_APP}
    WriteLn('    - Unix (仅Linux平台引入)');
  {$ENDIF}
  
  WriteLn;
  WriteLn('演示了 Pascal 中条件编译的各种用法');
  
  // 等待用户按键，防止程序窗口立即关闭
  ReadLn;
end.